package com.zikao.user.shiroConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zikao.user.entity.UserEntity;
import com.zikao.user.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * @Author: Likaisheng
 * @Description:
 * @Date: Created in 19:16:50 2021-03-06
 * @Modified By:
 */
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    public ShiroRealm() {
        super();
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        // 设置加密算法
        credentialsMatcher.setHashAlgorithmName("MD5");
        // 设置加密次数
        credentialsMatcher.setHashIterations(4);
        this.setCredentialsMatcher(credentialsMatcher);
    }

    // 授权会被shiro回调的方法
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //1、从PrincipalCollection中获取登录用户的信息
        Object principal = principals.getPrimaryPrincipal();

        //2、利用登录的用户信息来获取当前用户的角色或权限(可能需要查询数据库)
        QueryWrapper userWrapper = new QueryWrapper();
        userWrapper.eq("email",principal);
        UserEntity user = userService.getOne(userWrapper);

        Set<String> roles = new HashSet<>();
        // user-普通用户角色,admin-管理员角色
        roles.add("user");
        if (user.getIsAdmin() == 1){
            roles.add("admin");
        }

        //3、创建SimpleAuthorizationInfo,并设置realms属性
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);

        //4、返回SimpleAuthorizationInfo对象
        return info;
    }

    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1. 把AuthenticationToken转换为UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        
        //2. 从UsernamePasswordToken中来获取username
        String username = upToken.getUsername();

        //3. 调用数据库方法，从数据库查询username对应的用户记录
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("email",username);
        UserEntity user = userService.getOne(wrapper);

        //4. 若用户不存在，则可以抛出UnknownAccountException异常
        if (user == null){
            throw new UnknownAccountException("用户不存在!");
        }
        if (user.getIsActivated() == 0){
            throw new AccountException("该用户尚未激活，请点击邮箱里的激活链接进行激活!");
        }

        //5. 根据用户信息的情况，决定是否需要抛出其他的AuthenticationException异常

        //6. 根据用户的情况，来构建AuthenticationInfo对象并返回，通常使用的实现类为：SimpleAuthenticationInfo
        //以下信息是从数据库中获取的
        //1)、principal: 认证的实体信息，可以是username，也可以是数据表对应的用户的实体类对象.
        Object principal = user.getEmail();
        //2)、credentials: 密码
        Object credentials = user.getPwd();

        //3)、realmName：当前realm对象的name，调用父类的getName()方法即可
        String realmName = getName();
        //4)、盐值
        ByteSource salt = ByteSource.Util.bytes(username);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, salt,realmName);
        return info;
    }
}
